﻿#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
#include <QTextCodec>
#include <QMessageBox>
#include "mainwindow.h"
#include "ui_mainwindow.h"

#define MAXBASELEN (512)

static const char *ALPHA_BASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

char *MainWindow::encode(const char *buf, char *base64Char, unsigned int size) {
    int a = 0;
    unsigned int i = 0;
    while (i < size) {
        char b0 = buf[i++];
        char b1 = (i < size) ? buf[i++] : 0;
        char b2 = (i < size) ? buf[i++] : 0;

        int int63 = 0x3F; //  00111111
        int int255 = 0xFF; // 11111111
        base64Char[a++] = ALPHA_BASE[(b0 >> 2) & int63];
        base64Char[a++] = ALPHA_BASE[((b0 << 4) | ((b1 & int255) >> 4)) & int63];
        base64Char[a++] = ALPHA_BASE[((b1 << 2) | ((b2 & int255) >> 6)) & int63];
        base64Char[a++] = ALPHA_BASE[b2 & int63];
    }
    switch (size % 3) {
        case 1:
            base64Char[--a] = '=';
        case 2:
            base64Char[--a] = '=';
    }
    return base64Char;
}

unsigned int MainWindow::decode(const char *base64Char,
                         unsigned int base64CharSize,
                         char *originChar,
                         unsigned int originCharSize) {
    int toInt[128] = {-1};
    for (unsigned int i = 0; i < 64; i++) {
        toInt[ALPHA_BASE[i]] = i;
    }

    //int int255 = 0xFF;
    unsigned int index = 0;

    for (unsigned int i = 0; i < base64CharSize; i += 4) {
        int c0 = toInt[base64Char[i]];
        int c1 = toInt[base64Char[i + 1]];
        originChar[index++] = (((c0 << 2) | (c1 >> 4)) & 0xFF);
        if (index >= originCharSize) {
            return index;
        }
        int c2 = toInt[base64Char[i + 2]];
        originChar[index++] = (((c1 << 4) | (c2 >> 2)) & 0xFF);
        if (index >= originCharSize) {
            return index;
        }
        int c3 = toInt[base64Char[i + 3]];
        originChar[index++] = (((c2 << 6) | c3) & 0xFF);
    }
    return index;
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //this->setWindowTitle(QStringLiteral("Base64&Hex转换工具"));
    //this->setWindowTitle(QString::fromLocal8Bit("Base64&Hex转换工具"));
    //QTextCodec *codec = QTextCodec::codecForName("GBK");//修改这两行
    //this->setWindowTitle(codec->toUnicode("Base64&Hex转换工具"));
    this->setFixedSize(this->width(), this->height());
}

int MainWindow::hexStrToChar(char ch)
{
    if(ch >= '0' && ch <= '9') {
        return ch - '0';
    }

    if(ch >= 'a' && ch <= 'f') {
        return ch - 'a' + 10;
    }

    if(ch >= 'A' && ch <= 'F') {
        return ch - 'A' + 10;
    }

    return 0xff;
}

QByteArray MainWindow::hexStrToByteArray(const QString& data)
{
    QByteArray tmp;

    int len = data.length(), i, j;
    tmp.resize(len/2);

    int hhex, lhex;
    for(i = 0, j = 0; i < len;) {
        char hch = data.at(i).toLatin1();
        if(hch == ' ' ) {
            i++;
            continue;
        }
        i++;
        if(i >= len) break;
        hhex = hexStrToChar(hch);

        char lch = data.at(i).toLatin1();
        lhex = hexStrToChar(lch);

        i++;

        //左字符出错 || 右字符出错且不是空格跳过
        if(hhex == 0xff) continue;
        if(lhex == 0xff && lch != ' ') continue;
        //右字符是空格，则左字符按单字符补0处理
        if(lhex != 0xff) {
            hhex = hhex * 16 + lhex;
        }
        tmp[j] = static_cast<char>(hhex);
        j++;
    }

    if(j < len/2) {
        tmp.remove(j, len/2 - j);
    }

    return tmp;
}

int16_t MainWindow::GdecBase64(const char* indata, char *outdata, uint16_t inlen)
{
    uint16_t i,j, z = 0;
    uint16_t tlength = 0;
    uint8_t* buff = new uint8_t[inlen+10];

    //1、首先去掉最后1个或者2个'='字符，最多就是2个
    if(indata[inlen - 1] == '=') {
        inlen--;
        z++;
    }
    if(indata[inlen - 1] == '=') {
        inlen--;
        z++;
    }

    for(i = 0;i < inlen;i++){
        for(j = 0;j < 64;j++) {
            if(*(indata + i) == *(ALPHA_BASE + j))
                break;
        }
        if(j == 64) {//传输数据里面有错误数据，数据没在base64编码对照表里面
            return 0;
        }
        buff[i] = j;//找对对应索引值保存起来，为后面合成数据
    }
    //判断数据是否够4的倍数，不够补齐，补0x00
    if((i % 4) == 1)//说明数据最后剩余1数据，所以需要补充3个0x00,组成4的倍数
    {
        buff[i] = 0x00;
        buff[i + 1] = 0x00;
        buff[i + 2] = 0x00;
        i = i + 3;
    }
    if((i % 4) == 2)//说明数据最后剩余2数据，所以需要补充2个0x00,组成4的倍数
    {
        buff[i] = 0x00;
        buff[i + 1] = 0x00;
        i = i + 2;
    }
    if((i % 4) == 3)//说明数据最后剩余3数据，所以需要补充1个0x00,组成4的倍数
    {
        buff[i] = 0x00;
        i = i + 1;
    }
    for(j = 0,tlength = 0;j < i;j = j + 4,tlength = tlength + 3)//上面数据已经组成4的倍数了，这样转换后的数据一定是3的倍数，这样解码后数据可能比原来多几个0x00数据，如果你不希望多出几个0x00,其实你也可以不组成4的倍数，我这里主要是为了方便解码
    {
        outdata[tlength] = (buff[j] << 2) | ((buff[j + 1]&0x30) >> 4);
        outdata[tlength + 1] = (((buff[j + 1]&0x0F) << 4) | ((buff[j + 2]&0x3C) >> 2));
        outdata[tlength + 2] = (((buff[j + 2]&0x03) << 6) | buff[j + 3]);
    }

    delete [] buff;

    return tlength - z;
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_ConfigButton_clicked()
{
    QString input = ui->InputTxtEdit->toPlainText();
    input.replace(" ", "");
    //input = input.toUpper();  //base64区分大小写,不同转换,防止解码错误
    quint32 len = input.length();

    if(len > 1024 || len == 0) {
        QMessageBox::information(0, "warning", u8"串长不能大于1024或为0");
        return;
    }

    if(ui->Base64toHexRadioBtn->isChecked()) {
        try {
            char* buf = new char[len * 2];
            memset(buf, 0, len * 2);
            //unsigned int sz = decode(input.toStdString().c_str(), len, buf, 512);
            unsigned int sz = GdecBase64(input.toStdString().c_str(), buf, len);

            if(sz > 0) {
                QByteArray data = QByteArray(buf, sz);
                QString temp = "";
                QString hex = data.toHex();

                for (int i = 0; i < hex.length(); i = i + 2) {
                    temp += hex.mid(i, 2) + " ";
                }

                temp = temp.trimmed().toUpper();
                ui->RetTxtEdit->setText(temp);

                QString log = QString(u8"base64串长:%1,16进制串长%2").arg(len).arg(hex.length());
                ui->tipsLable->setText(log);
            }
            else {
                QMessageBox::information(0, "warning", u8"非法的Base64串");
            }

            delete [] buf;
        }
        catch(...) {
            QMessageBox::information(0, "warning", "Base64 to Hex Failed");
        }
    }
    else if(ui->HextoBase64RadioBtn->isChecked()) {
        char* buf = new char[len * 4 + 10];
        memset(buf, 0, len * 4 + 10);

        int i = 0, j = 0;
        for(i = 0; i < len; i++) {
            if((input.at(i) >= '0' && input.at(i) <= '9')
            || (input.at(i) >= 'A' && input.at(i) <= 'F')
            || (input.at(i) >= 'a' && input.at(i) <= 'f')) {
                j++;
            }
        }
        if(i != j) {
            QMessageBox::information(0, "warning", u8"非法的16进制串");
        }
        else {
            QByteArray data2 = hexStrToByteArray(input);
            encode(data2.constData(), buf, len/2);
            QByteArray data = QByteArray(buf);
            QString temp = QString(data);
            ui->RetTxtEdit->setText(temp);

            QString log = QString(u8"base64串长:%1,16进制串长%2").arg(data.length()).arg(len);
            ui->tipsLable->setText(log);
        }
        delete [] buf;
    }
}

void MainWindow::on_ClrPushButton_clicked()
{
    ui->InputTxtEdit->clear();
}

void MainWindow::on_CalcButton_clicked()
{
    if(ui->Base10toHexRadioBtn->isChecked()) {
        QString dicimal = ui->DicimalLineEdit->text();
        dicimal = dicimal.trimmed();
        if(dicimal.isEmpty()) return;

        QByteArray dicimalByte = dicimal.toLatin1();
        const char* data = dicimalByte.data();
        while(*data && *data >= '0' && *data <= '9') data++;
        if(*data)  {
            QMessageBox::information(0, "warning", u8"非法的10进制串");
            return;
        }
        qlonglong di = dicimalByte.toLongLong();
        ui->HexLineEdit->setText(QString::number(di, 16).toUpper());
    }
    else if(ui->HextoBase10RadioBtn->isChecked()) {
        QString hex = ui->HexLineEdit->text();
        hex.replace(" ", "");
        hex = hex.trimmed().toUpper();
        if(hex.isEmpty()) return;

        QByteArray hexByte = hex.toLatin1();
        const char*data = hexByte.data();
        while(*data && ((*data >= '0' && *data <= '9') || (*data >= 'A' && *data <= 'F'))) data++;
        if(*data) {
            QMessageBox::information(0, "warning", u8"非法的16进制串");
            return;
        }
        qlonglong di = hexByte.toLongLong(0, 16);
        ui->DicimalLineEdit->setText(QString::number(di));
    }
}
